#ifndef WIDGETLIBRARY_H
#define WIDGETLIBRARY_H

#include <type_traits>
#include <QtWidgets/QtWidgets>
#include <QtGui/QtGui>
#include <memory>

#include <tchar.h>
#include <windows.h>
template<class WIDGET>
class desktop_widget:public WIDGET
{
	typedef WIDGET BASE;

	//////////////////////////////////////////////////////////////////////////
	//
	template<bool _Widget>
	struct widget_window
	{
		widget_window(QWidget* _this)
			:_this(_this)
		{
		}
		widget_window* operator->()
		{
			return this;
		}
		void move(int x,int y) 
		{
			_this->move(x,y);
		}
		void move(QPoint const& pt) 
		{
			_this->move(pt);
		}
		QPoint pos() const
		{
			return _this->pos();
		}
		QWidget* _this;
	};
	

	template<>
	struct widget_window<false>
	{
		widget_window(QWindow* _this)
			:_this(_this)
		{
		}
		
		widget_window* operator->()
		{
			return this;
		}
		void move(int x,int y) 
		{
			_this->setFramePosition(QPoint(x,y));
		}
		void move(QPoint const& pt) 
		{
			_this->setFramePosition(pt);
		}

		QPoint pos() const
		{
			return _this->framePosition();
		}
		QWindow* _this;
	};

public:

	desktop_widget(typename std::conditional<std::is_base_of<QWidget, WIDGET>::value,
		QWidget,
		typename std::conditional<std::is_base_of<QWindow,WIDGET>::value,QWindow,QObject>::type 
	>::type  *parent=0);



	void SetDragMoveEnable(bool enable=true)
	{
		bDragMove=enable;
	}
	void SetAutoDock(bool enable=true)
	{
		bAutoDock=enable;
	}
	void SetMouseThrough(bool enable=true)
	{
		bMouseThrough=enable;
		auto style=	::GetWindowLongPtr((HWND)this->winId(),GWL_EXSTYLE);
		bMouseThrough ?	style|=WS_EX_TRANSPARENT : style&=~WS_EX_TRANSPARENT;
		::SetWindowLongPtr((HWND)this->winId(),GWL_EXSTYLE,style);
	}
	void SetTopMost(bool enable=true)
	{
		bTopMost=enable;
		auto style=	this->windowFlags();
		if (bTopMost)
		{
			style|=Qt::WindowStaysOnTopHint ;
		}
		else
		{
			style&=~Qt::WindowStaysOnTopHint;
		}
		this->setWindowFlags(style);
	}
	void SetStayInsideScreen(bool enable=true)
	{
		bStayInsideScreen=enable;
	}	
protected:

	bool event(QEvent* ev) override
	{
		switch (ev->type())
		{
		case QEvent::MouseButtonRelease:
			{
				QMouseEvent* e=(QMouseEvent*)ev;
				if (e->button()==Qt::MouseButton::LeftButton)
				{
					bpressed=false;
				}
				return BASE::event(ev);
			}
			break;
		case QEvent::MouseButtonPress:
			{
				QMouseEvent* e=(QMouseEvent*)ev;
				if (e->button()==Qt::MouseButton::LeftButton)
				{
					bpressed=bDragMove;
					dragPos=e->globalPos()-widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->pos();
				}
				return BASE::event(ev);
			}break;
		case QEvent::MouseMove:
			{
				QMouseEvent* e=(QMouseEvent*)ev;
				if ( bpressed && e->buttons()&Qt::MouseButton::LeftButton)
				{
					QRect screen=QApplication::desktop()->geometry();
					auto newPos=e->globalPos()-dragPos;
					QRect rect=this->geometry();
					rect.moveTo(newPos);

					if (!bStayInsideScreen || screen.contains(rect))
					{
						widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->move(newPos);
					}
					else
					{
						dragPos=e->globalPos()-widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->pos();
					}
				}
				return BASE::event(ev);
			}break;
		default:
			return BASE::event(ev);
			break;
		}
		return true;
	}

private:
	bool					bDragMove;
	bool					bAutoDock;
	bool					bMouseThrough;
	bool					bTopMost;
	bool					bStayInsideScreen;
	QPoint	dragPos;
	QTimer	timerDock;

	int		testTimes;
	bool	bpressed;
};



static inline BOOL CALLBACK EnumWinProc(HWND hwnd,LPARAM outHwnd)
{
	HWND hWndShellDLL = FindWindowExW(hwnd, NULL, L"SHELLDLL_DefView", NULL);
	if (hWndShellDLL!=nullptr)
	{
		*((HWND*)outHwnd)=hWndShellDLL;
		return FALSE;
	}
	return TRUE;
}

inline void KeepOnDeskTop(HWND hWnd)
{
	HWND hWndProgram = NULL;
	HWND hWndShellDLL = NULL;
	hWndProgram = FindWindowW(L"Progman", L"Program Manager");
	if(hWndProgram != NULL)
	{
		hWndShellDLL = FindWindowExW(hWndProgram, NULL, L"SHELLDLL_DefView", NULL);
	}
	if(hWndShellDLL == NULL)
	{
		EnumWindows(EnumWinProc,(LPARAM)&hWndShellDLL);
	}	
	SetWindowLongPtrW(hWnd, GWL_HWNDPARENT, (LONG)hWndShellDLL);
	::SetWindowPos(hWnd,HWND_BOTTOM ,0,0,0,0,SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE | SWP_NOSIZE|SWP_FRAMECHANGED);
}


template<class WIDGET>
desktop_widget<WIDGET>::desktop_widget(typename std::conditional<std::is_base_of<QWidget,WIDGET>::value, 
	QWidget,typename std::conditional<std::is_base_of<QWindow,WIDGET>::value, 
	QWindow,QObject>::type >::type *parent/*=0*/ )
	:WIDGET(parent)
	,bpressed(false)
	,timerDock()
	,testTimes(0)
	,bDragMove(false)
	,bMouseThrough(false)
	,bAutoDock(false)
	,bTopMost(false)
	,bStayInsideScreen(false)
{

	//this->setWindowFlags(Qt::WindowType::FramelessWindowHint);
	//this->setAttribute(Qt::WA_TranslucentBackground);
	//this->setStyleSheet("border:0px;\n"  "background-color:transparent;");

	//KeepOnDeskTop((HWND)this->winId());
	//SetDragMoveEnable();

	this->connect(&timerDock,&QTimer::timeout,[this](){
		QRect rect=this->geometry();
		QRect screen=QApplication::desktop()->geometry();

#define _left	abs(rect.left()-screen.left())
#define _top	abs(rect.top()-screen.top())
#define _down	abs(rect.bottom()-screen.bottom())
#define _right	abs(rect.right()-screen.right())

		if ( _left<20 && _left >2)
		{
			widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->move(screen.left(),rect.top());
		}

		if (_right<20&& _right>2)
		{
			widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->move(screen.right()-rect.width(),rect.top());
		}

		if ( _top<20 && _top >2)
		{
			widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->move(rect.left(),screen.top());
		}

		if (_down<20&& _down >2) 
		{
			widget_window<std::is_base_of<QWidget,WIDGET>::value >(this)->move(rect.left(),screen.bottom()-rect.height());
		}
		if (++testTimes >3)
		{
			testTimes=0;
			timerDock.stop();
		}
	});

}



#endif // WIDGETLIBRARY_H
